"""Global error handling and standardized responses."""

from __future__ import annotations

import logging
import traceback
from enum import IntEnum
from typing import Any

from fastapi import HTTPException, Request
from fastapi.exceptions import RequestValidationError
from fastapi.responses import JSONResponse
from starlette import status


logger = logging.getLogger(__name__)


class BusinessErrorCode(IntEnum):
    """业务错误码枚举.

    错误码分类:
    - 1000-1999: 认证与授权相关
    - 2000-2999: 项目管理相关
    - 3000-3999: 用户管理相关
    - 9000+: 系统错误

    使用示例:
        raise HTTPException(
            status_code=400,
            detail=f"错误码 {BusinessErrorCode.INVALID_CREDENTIALS}: 用户名或密码错误"
        )
    """

    # === 认证与授权 (1000-1999) ===
    INVALID_CREDENTIALS = 1001  # 用户名或密码错误
    TOKEN_EXPIRED = 1002  # Token 已过期
    TOKEN_INVALID = 1003  # Token 无效
    EMAIL_ALREADY_EXISTS = 1004  # 邮箱已存在
    USER_NOT_FOUND = 1005  # 用户不存在
    INSUFFICIENT_PERMISSIONS = 1006  # 权限不足
    ACCOUNT_DISABLED = 1007  # 账户已禁用

    # === 项目管理 (2000-2999) ===
    PROJECT_NOT_FOUND = 2001  # 项目不存在
    PROJECT_NAME_DUPLICATE = 2002  # 项目名称重复
    PROJECT_PERMISSION_DENIED = 2003  # 无权限访问该项目
    PROJECT_STATUS_INVALID = 2004  # 项目状态无效

    # === 用户管理 (3000-3999) ===
    USER_PROFILE_INCOMPLETE = 3001  # 用户资料不完整
    PASSWORD_TOO_WEAK = 3002  # 密码强度不足
    EMAIL_VERIFICATION_REQUIRED = 3003  # 需要邮箱验证

    # === 系统错误 (9000+) ===
    DATABASE_ERROR = 9001  # 数据库错误
    INTERNAL_ERROR = 9999  # 内部错误


def format_response(code: int, message: str, data: object | None = None) -> dict[str, Any]:
    """Create a standardized JSON structure used by legacy API utils.

    Note: New endpoints should prefer returning plain Pydantic models
    per RESTful standards. This helper exists to maintain backward
    compatibility for existing utilities.
    """
    return {
        "code": code,
        "message": message,
        "data": data,
    }


async def http_exception_handler(_: Request, exc: HTTPException) -> JSONResponse:
    """
    Handle FastAPI HTTP exceptions.
    Returns standard RESTful error format: {detail: string}
    """
    detail = exc.detail if exc.detail else exc.__class__.__name__
    return JSONResponse(
        status_code=exc.status_code,
        content={"detail": detail}
    )


async def validation_exception_handler(_: Request, exc: RequestValidationError) -> JSONResponse:
    """
    Handle Pydantic validation errors.
    Returns standard RESTful error format: {detail: string}
    """
    # Convert validation errors to serializable format
    errors = []
    for error in exc.errors():
        # Create a clean serializable copy
        clean_error = {
            "type": error.get("type"),
            "loc": error.get("loc"),
            "msg": error.get("msg"),
            "input": error.get("input"),
        }

        # Convert ctx values to strings (handles ValueError, etc.)
        if "ctx" in error:
            clean_error["ctx"] = {k: str(v) for k, v in error["ctx"].items()}

        errors.append(clean_error)

    # Standard RESTful error format
    return JSONResponse(
        status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
        content={
            "detail": errors
        },
    )


async def server_error_handler(request: Request, exc: Exception) -> JSONResponse:  # pragma: no cover
    """
    Handle unexpected server errors.
    Returns standard RESTful error format: {detail: string}
    """
    # Log the full exception with traceback
    import sys
    print(f"\n{'='*60}", file=sys.stderr)
    print(f"ERROR on {request.url.path}:", file=sys.stderr)
    print(f"{exc}", file=sys.stderr)
    print(traceback.format_exc(), file=sys.stderr)
    print("="*60, file=sys.stderr)

    logger.error(f"Unhandled exception on {request.url.path}: {exc}")
    logger.error(traceback.format_exc())

    return JSONResponse(  # pragma: no cover
        status_code=status.HTTP_500_INTERNAL_SERVER_ERROR,
        content={
            "detail": "Internal server error"
        },
    )


